home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / gkismet / Locator.pm < prev    next >
Text File  |  2005-10-20  |  14KB  |  513 lines

  1. #!/usr/bin/perl -w
  2. #
  3. # $Id: Locator.pm,v 1.16 2003/08/04 04:57:02 solovam Exp $
  4. #
  5. # This file is a part of gkismet
  6. #
  7. # This program is free software; you can redistribute it and/or
  8. # modify it under the terms of the GNU General Public License
  9. # as published by the Free Software Foundation; either version 2
  10. # of the License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20. #
  21.  
  22. #
  23. # Locator class
  24. #
  25. package Locator;
  26.  
  27. use Gnome;
  28. use Math::Trig;
  29. use Math::Complex;
  30. use Misc;
  31. use BssConnObserver;
  32. use DrawingArea;
  33. use strict;
  34. @Locator::ISA = qw(BssConnObserver);
  35.  
  36. my $minHeadingDist = 10;
  37. my $compassWidth = 400;
  38. my $compassHeight = 60;
  39. my @currCoordLabels = ('Longitude', 'Latitude', 'Bearing', 'Fix');
  40. my @netCoordLabels = ('Longitude', 'Latitude', 'Distance', 'Bearing');
  41.  
  42. #
  43. # Constructor
  44. #
  45. sub new
  46. {
  47.     my $type = shift;
  48.     my $self = new BssConnObserver(@_);
  49.     bless $self, $type;
  50.  
  51.     # Check if there are GPS data
  52.     if(!defined $self->{'connection'}->getGps()->{'lat'} || $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'aggpoints'} == 0)
  53.     {
  54.         my $messagebox = new Gnome::MessageBox("No GPS data for network bssid: " . $self->{'bssid'}, 'error', 'Button_Ok');
  55.         $messagebox->run_and_close();
  56.         return undef;
  57.     }
  58.  
  59.     # Init vars
  60.     $self->{'mode'} = 'averageCenter';
  61.     $self->{'lastLat'} = $self->{'connection'}->getGps()->{'lat'}; 
  62.     $self->{'lastLon'} = $self->{'connection'}->getGps()->{'lon'}; 
  63.     $self->{'headingAngle'} = 0;
  64.     $self->recalculate();
  65.  
  66.     # Window
  67.     my $window = new Gtk::Window('dialog');
  68.     $window->signal_connect("delete_event", sub {$self->deleteHandler()});
  69.     $window->set_title('Network locator ' . $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'ssid'} . ' ' . $self->{'bssid'});
  70.     $self->{'window'} = $window;
  71.  
  72.     # Drawing area
  73.     $self->{'drawingArea'} = new DrawingArea($compassWidth, $compassHeight, sub {$self->drawCompass()});
  74.     my $compassFrame = new Gtk::Frame(undef);
  75.     $compassFrame->add($self->{'drawingArea'}->getWidget());
  76.     my $fixed = new Gtk::Fixed();
  77.     $fixed->put($compassFrame, 0, 0);
  78.     my $compassHbox= new Gtk::HBox($true, 0);
  79.     $compassHbox->pack_start($fixed, $true, $false, 20);
  80.  
  81.     # Labels
  82.     my $currCoordFrame = new Gtk::Frame(undef);
  83.     $self->{'currCoordFrame'} = $currCoordFrame;
  84.     $currCoordFrame->set_label('Current coordinates');
  85.     my $currCoordVbox = new Gtk::VBox($false, 5);
  86.     $currCoordFrame->add($currCoordVbox);
  87.     for my $l (@currCoordLabels)
  88.     {
  89.         my $hbox = new Gtk::HBox($false, 1);
  90.  
  91.         my $nlabel = new Gtk::Label($l . ': ');
  92.         $nlabel->set_justify('left');
  93.         $hbox->pack_start($nlabel, $false, $false, 5);
  94.  
  95.         my $vlabel = new Gtk::Label('');
  96.         $vlabel->set_justify('right');
  97.         $hbox->pack_end($vlabel, $false, $false, 5);
  98.  
  99.         $currCoordVbox->pack_start($hbox, $false, $false, 3);
  100.         
  101.         $self->{'currCoordLabel'}{$l} = $vlabel;
  102.     }
  103.     my $netCoordFrame = new Gtk::Frame(undef);
  104.     $self->{'netCoordFrame'} = $netCoordFrame;
  105.     $netCoordFrame->set_label('Average network center');
  106.     my $netCoordVbox = new Gtk::VBox($false, 5);
  107.     $netCoordFrame->add($netCoordVbox);
  108.     for my $l (@netCoordLabels)
  109.     {
  110.         my $hbox = new Gtk::HBox($false, 1);
  111.  
  112.         my $nlabel = new Gtk::Label($l . ': ');
  113.         $nlabel->set_justify('left');
  114.         $hbox->pack_start($nlabel, $false, $false, 5);
  115.  
  116.         my $vlabel = new Gtk::Label('');
  117.         $vlabel->set_justify('right');
  118.         $hbox->pack_end($vlabel, $false, $false, 5);
  119.  
  120.         $netCoordVbox->pack_start($hbox, $false, $false, 3);
  121.         
  122.         $self->{'netCoordLabel'}{$l} = $vlabel;
  123.     }
  124.     $self->updateLabels();
  125.  
  126.     # Buttons
  127.     my $bbox = new Gtk::HButtonBox();
  128.     $bbox->set_layout('spread');
  129.     $bbox->set_spacing(5);
  130.     my $buttonClose = new Gtk::Button("Close");
  131.     $buttonClose->signal_connect( "clicked", sub {$self->closeClicked()});
  132.     $bbox->add($buttonClose);
  133.     my $buttonMode = new Gtk::Button("Mode");
  134.     $buttonMode->signal_connect( "clicked", sub {$self->modeClicked($buttonMode)});
  135.     $bbox->add($buttonMode);
  136.  
  137.     # Assemble
  138.     my $hbox = new Gtk::HBox($true, 0);
  139.     $hbox->pack_start($currCoordFrame, $true, $true, 20);
  140.     $hbox->pack_start($netCoordFrame, $true, $true, 20);
  141.     my $vbox = new Gtk::VBox($false, 10);
  142.     $vbox->pack_start($compassHbox, $true, $false, 20);
  143.     $vbox->pack_start($hbox, $true, $false, 0);
  144.     $vbox->pack_start($bbox, $true, $false, 20);
  145.     $window->add($vbox);
  146.     $window->show_all();
  147.  
  148.     # Start updates
  149.     $self->{'connection'}->addObserver($self);
  150.  
  151.     return $self;
  152. }
  153.  
  154. #
  155. # Update labels
  156. #
  157. sub updateLabels
  158. {
  159.     my $self = shift;
  160.     $self->{'currCoordLabel'}{'Latitude'}->set_text(sprintf "%.6f", $self->{'lat'});
  161.     $self->{'currCoordLabel'}{'Longitude'}->set_text(sprintf "%.6f", $self->{'lon'});
  162.     $self->{'currCoordLabel'}{'Bearing'}->set_text(sprintf "%.0f", $self->{'headingAngle'});
  163.     my $fix;
  164.     if($self->{'fix'} == -1)
  165.     {
  166.         $fix = 'No signal';
  167.     }
  168.     elsif($self->{'fix'} == 2)
  169.     {
  170.         $fix = '2D';
  171.     }
  172.     elsif($self->{'fix'} == 3)
  173.     {
  174.         $fix = '3D';
  175.     }
  176.     else
  177.     {
  178.         $fix = 'NONE';
  179.     }
  180.     $self->{'currCoordLabel'}{'Fix'}->set_text($fix);
  181.     $self->{'netCoordLabel'}{'Latitude'}->set_text(sprintf "%.6f", $self->{'centerLat'});
  182.     $self->{'netCoordLabel'}{'Longitude'}->set_text(sprintf "%.6f", $self->{'centerLon'});
  183.     $self->{'netCoordLabel'}{'Bearing'}->set_text(sprintf "%.0f", $self->{'centerAngle'});
  184.     my $dist = '';
  185.     if($self->{'gKismetApplication'}->{'preferences'}->getPref('units') eq 'metric')
  186.     {
  187.         if($self->{'dist'} < 1000)
  188.         {
  189.             $dist = sprintf("%.2fm", $self->{'dist'});
  190.         }
  191.         else
  192.         {
  193.             $dist = sprintf("%.3fkm", $self->{'dist'} / 1000);
  194.         }
  195.     }
  196.     else
  197.     {
  198.         if($self->{'dist'} / $mileFactor > 0.5)
  199.         {
  200.             $dist = sprintf("%.3fmi", $self->{'dist'} / $mileFactor);
  201.         }
  202.         else
  203.         {
  204.             $dist = sprintf("%.2fft", $self->{'dist'} / $footFactor);
  205.         }
  206.     }
  207.     $self->{'netCoordLabel'}{'Distance'}->set_text($dist);
  208. }
  209.  
  210. #
  211. # Change network locator mode
  212. #
  213. sub modeClicked
  214. {
  215.     my $self = shift;
  216.     if($self->{'mode'} eq 'averageCenter')
  217.     {
  218.         $self->{'mode'} = 'strongestSignal';
  219.         $self->{'netCoordFrame'}->set_label('Strongest signal point');
  220.     }
  221.     elsif($self->{'mode'} eq 'strongestSignal')
  222.     {
  223.         $self->{'mode'} = 'averageCenter';
  224.         $self->{'netCoordFrame'}->set_label('Average network center');
  225.     }
  226.     $self->recalculate();
  227.     $self->drawCompass();
  228.     $self->updateLabels();
  229. }
  230.  
  231. #
  232. # Draw our compass into the pixmap
  233. #
  234. sub drawCompass
  235. {
  236.     my $self = shift;
  237.  
  238.     # Abbreviations
  239.     my $pixmap = $self->{'drawingArea'}->pixmap();
  240.     my $gtkDrawingArea = $self->{'drawingArea'}->gtkDrawingArea();
  241.  
  242.     # Backdrop
  243.     $pixmap->draw_rectangle($gtkDrawingArea->style()->black_gc(), $true,
  244.         0, 0, $gtkDrawingArea->allocation()->[2], $gtkDrawingArea->allocation()->[3]);
  245.  
  246.     # Middle horizontal white line
  247.     $pixmap->draw_line($gtkDrawingArea->style()->white_gc(), 0, $compassHeight/2, $compassWidth, $compassHeight/2);
  248.  
  249.     # Red vertical line
  250.     $pixmap->draw_line($self->{'drawingArea'}->{'redGC'}, $compassWidth/2, 0, $compassWidth/2, $compassHeight);
  251.  
  252.     # Digits on the gauge every 30 degrees
  253.     for(my $i = 0; $i < 12; $i++)
  254.     {
  255.         # Linear position of a mark
  256.         my $l = $self->deg2pix($i * 30);
  257.         # Draw a mark
  258.         $pixmap->draw_line($gtkDrawingArea->style()->white_gc(), $l, $compassHeight / 2 + 5, $l, $compassHeight / 2 - 5);
  259.         # Draw a label
  260.         $pixmap->draw_string($gtkDrawingArea->style()->font(), $gtkDrawingArea->style()->white_gc(),
  261.             # Shift text left by half of string length
  262.             $l - $self->{'drawingArea'}->stringWidth($i * 30) / 2,
  263.             # Shift text down from the middle by mark height (5) + padding (5) + string height
  264.             $compassHeight / 2 + 5 + $self->{'drawingArea'}->stringHeight($i * 30) + 5,
  265.             $i * 30);
  266.     }
  267.  
  268.     # North, south, west, east letters. Pretty mach same as above
  269.     for my $i ([0, 'N'], [90, 'E'], [180, 'S'], [270, 'W'])
  270.     {
  271.         my $l = $self->deg2pix($i->[0]);
  272.         $pixmap->draw_string($gtkDrawingArea->style()->font(), $gtkDrawingArea->style()->white_gc(),
  273.             $l - $self->{'drawingArea'}->stringWidth($i->[1]) / 2,
  274.             $compassHeight / 2 - 5 - 5,
  275.             $i->[1]);
  276.     }
  277.  
  278.     # Linear position of the center angle mark
  279.     my $l = $self->deg2pix($self->{'centerAngle'});
  280.     # A little triangle
  281.     my @triangle = ($l - 5, $compassHeight, $l, $compassHeight - 5, $l + 5, $compassHeight);
  282.     $pixmap->draw_polygon($self->{'drawingArea'}->{'redGC'}, $true, @triangle);
  283.  
  284.     # Redraw us
  285.     $gtkDrawingArea->draw();
  286.  
  287.     return;
  288. }
  289.  
  290. #
  291. # Translate degress into pixels on our compass scale
  292. #
  293. sub deg2pix
  294. {
  295.     my $self = shift;
  296.     my $deg = shift;
  297.  
  298.     my $l = ($deg - $self->{'headingAngle'}) * $compassWidth / 360 + $compassWidth * 3/2;
  299.  
  300.     while ($l >= $compassWidth)
  301.     {
  302.         $l -= $compassWidth;
  303.     }
  304.  
  305.     return $l;
  306. }
  307.  
  308. #
  309. # Handle an update from an observable
  310. #
  311. sub update
  312. {
  313.     my $self = shift;
  314.     my $object = shift;
  315.     my $data = shift;
  316.  
  317.     if($object->isa('Connection') && defined $self->{'connection'} && $self->{'connection'} eq $object)
  318.     {
  319.         if($data->{'changed'} eq 'gps' || ($data->{'changed'} eq 'network' && $data->{'bssid'} eq $self->{'bssid'}))
  320.         {
  321.             $self->recalculate();
  322.             $self->drawCompass();
  323.             $self->updateLabels();
  324.         }
  325.     }
  326. }
  327.  
  328. #
  329. # Repopulate coordinates, recalculate bearings and distance
  330. #
  331. sub recalculate
  332. {
  333.     my $self = shift;
  334.  
  335.     if($self->{'mode'} eq 'averageCenter')
  336.     {
  337.         $self->{'centerLat'} = $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'agglat'} /
  338.             $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'aggpoints'}; 
  339.         $self->{'centerLon'} = $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'agglon'} /
  340.             $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'aggpoints'};
  341.     }
  342.     elsif($self->{'mode'} eq 'strongestSignal')
  343.     {
  344.         $self->{'centerLat'} = $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'bestlat'};
  345.         $self->{'centerLon'} = $self->{'connection'}->getNetwork()->{$self->{'bssid'}}{'bestlon'};
  346.     }
  347.  
  348.     $self->{'lat'} = $self->{'connection'}->getGps()->{'lat'};
  349.     $self->{'lon'} = $self->{'connection'}->getGps()->{'lon'};
  350.     $self->{'fix'} = $self->{'connection'}->getGps()->{'fix'};
  351.     
  352.     $self->{'centerAngle'} = Locator->calcAngle($self->{'lat'}, $self->{'lon'}, $self->{'centerLat'}, $self->{'centerLon'});
  353.     $self->{'dist'} = Locator->earthDistance($self->{'lat'}, $self->{'lon'}, $self->{'centerLat'}, $self->{'centerLon'});
  354.  
  355.     if(Locator->earthDistance($self->{'lastLat'}, $self->{'lastLon'}, $self->{'lat'}, $self->{'lon'}) >= $minHeadingDist)
  356.     {
  357.         $self->{'headingAngle'} = Locator->calcAngle($self->{'lastLat'}, $self->{'lastLon'}, $self->{'lat'}, $self->{'lon'});
  358.         $self->{'lastLat'} = $self->{'lat'};
  359.         $self->{'lastLon'} = $self->{'lon'};
  360.     }
  361. }
  362.  
  363. #
  364. # Get Gtk widget
  365. #
  366. sub getWidget
  367. {
  368.     my $self = shift;
  369.     return $self->{'window'};
  370. }
  371.  
  372. #
  373. # Distance from the center of Earth in meters
  374. #
  375. # Taken (with some mods) from Kismet
  376. #
  377. sub calcRad
  378. {
  379.     my $type = shift;
  380.     my $lat = shift;
  381.     $lat = deg2rad($lat);
  382.     
  383.     # the radius of curvature of an ellipsoidal Earth in the plane of the
  384.     # meridian is given by
  385.     #
  386.     # R' = a * (1 - e^2) / (1 - e^2 * (sin(lat))^2)^(3/2)
  387.     #
  388.     # where a is the equatorial radius,
  389.     # b is the polar radius, and
  390.     # e is the eccentricity of the ellipsoid = sqrt(1 - b^2/a^2)
  391.     #
  392.     # a = 6378 km (3963 mi) Equatorial radius (surface to center distance)
  393.     # b = 6356.752 km (3950 mi) Polar radius (surface to center distance)
  394.     # e = 0.081082 Eccentricity
  395.  
  396.     my $a = 6378.137;
  397.     my $e2 = 0.081082 * 0.081082;
  398.     my $sc = sin($lat);
  399.     my $x = $a * (1.0 - $e2);
  400.     my $z = 1.0 - $e2 * $sc * $sc;
  401.     my $y = Misc->pow($z, 1.5);
  402.     my $r = $x / $y;
  403.     $r = $r * 1000;
  404.  
  405.     return $r;
  406. }
  407.  
  408. #
  409. # Distance between points in meters
  410. #
  411. # Taken (with some mods) from Kismet
  412. #
  413. sub earthDistance
  414. {
  415.     my $type = shift;
  416.     my ($lat1, $lon1, $lat2, $lon2) = (@_);
  417.     my $x1 = Locator->calcRad($lat1) * cos(deg2rad($lon1)) * sin(deg2rad(90 - $lat1));
  418.     my $x2 = Locator->calcRad($lat2) * cos(deg2rad($lon2)) * sin(deg2rad(90 - $lat2));
  419.     my $y1 = Locator->calcRad($lat1) * sin(deg2rad($lon1)) * sin(deg2rad(90 - $lat1));
  420.     my $y2 = Locator->calcRad($lat2) * sin(deg2rad($lon2)) * sin(deg2rad(90 - $lat2));
  421.     my $z1 = Locator->calcRad($lat1) * cos(deg2rad(90 - $lat1));
  422.     my $z2 = Locator->calcRad($lat2) * cos(deg2rad(90 - $lat2));
  423.     my $a = acos(($x1 * $x2 + $y1 * $y2 + $z1 * $z2) / Misc->pow(Locator->calcRad(($lat1 + $lat2) / 2), 2));
  424.     my $dist = Locator->calcRad(($lat1 + $lat2) / 2) * $a;
  425.     if(ref($dist) eq 'Math::Complex')
  426.     {
  427.         return 0;
  428.     }
  429.     return $dist;
  430. }
  431.  
  432. #
  433. # Azimuth
  434. #
  435. # Taken (with some mods) from Kismet
  436. #
  437. sub calcAngle
  438. {
  439.     my $type = shift;
  440.     my($lat1, $lon1, $lat2, $lon2) = (@_);
  441.  
  442.     my $R = Locator->calcRad($lat2);
  443.  
  444.     $lat1 = deg2rad($lat1);
  445.     $lon1 = deg2rad($lon1);
  446.     $lat2 = deg2rad($lat2);
  447.     $lon2 = deg2rad($lon2);
  448.  
  449.     my $angle;
  450.     # we are moving along parallel
  451.     if($lat1 == $lat2)
  452.     {
  453.         # east
  454.         if($lon2 > $lon1)
  455.         {
  456.             $angle = pi/2;
  457.         }
  458.         # west
  459.         elsif($lon2 < $lon1)
  460.         {
  461.             $angle = 3 * pi / 2;
  462.         }
  463.         # not moving at all
  464.         else
  465.         {
  466.             return(0);
  467.         }
  468.     }
  469.     # we are moving along meridian
  470.     elsif($lon1 == $lon2)
  471.     {
  472.         # north
  473.         if($lat2 > $lat1)
  474.         {
  475.             $angle = 0;
  476.         }
  477.         # south
  478.          elsif($lat2 < $lat1)
  479.         {
  480.             $angle = pi;
  481.         }
  482.         # we never get here
  483.         else
  484.         {
  485.             return(undef);
  486.         }
  487.     }
  488.     # otherwise we calculate heading
  489.     else
  490.     {
  491.         my $tx = $R * cos($lat1) * ($lon2 - $lon1);
  492.         my $ty = $R * ($lat2 - $lat1);
  493.         $angle = atan($tx / $ty);
  494.  
  495.         if ($ty < 0)
  496.         {
  497.             $angle += pi;
  498.         }
  499.         if($angle >= (2 * pi))
  500.         {
  501.             $angle -= 2 * pi;
  502.         }
  503.         if($angle < 0)
  504.         {
  505.             $angle += 2 * pi;
  506.         }
  507.     }
  508.  
  509.     return rad2deg($angle);
  510. }
  511.  
  512. 1;
  513.